#include "contactmanager.h"

#include "appchat/accountmanager.h"
#include "account/accountbuddy.h"
#include "account/accountbuddy.h"

#include "contactabstractcontact.h"
#include "contactprivatecontact.h"
#include "contactgroupcontact.h"

#include <QDebug>


namespace Contact {

Manager *Manager::m_instance = NULL;

Manager::Manager(QObject *parent) :
    QObject(parent)
{
    init();
    setConnection();
}


Manager::~Manager()
{
}


Manager *Manager::instance()
{
    if (m_instance == NULL)
        m_instance = new Manager();
    return m_instance;
}


void Manager::init()
{
    m_activeContact = NULL;
}


void Manager::setConnection() const
{

}


AbstractContact *Manager::findByIndex(int index) const
{
    if (index < 0 || index >= count())
        return NULL;

    return m_contactList.at(index);
}


PrivateContact *Manager::findPrivateContactById(qint64 id) const
{
    QMutexLocker locker(&m_mutex);
    ItemFinderIterator iterator = m_privateContactFinder.find(id);
    if (iterator == m_privateContactFinder.end())
        return NULL;

    PrivateContact *contact = dynamic_cast<PrivateContact *>(*iterator);
    return contact;
}


AbstractContact *Manager::findGroupContactById(qint64 id) const
{
    QMutexLocker locker(&m_mutex);
    ItemFinderIterator iterator = m_groupContactFinder.find(id);
    if (iterator == m_groupContactFinder.end())
        return NULL;

    return *iterator;
}


int Manager::indexOf(AbstractContact *contact) const
{
    if (contact == NULL)
        return -1;

    return m_contactList.indexOf(contact);
}


AbstractContact *Manager::at(int index) const
{
    if ((index < 0) || (index >= count()))
        return NULL;

    return m_contactList.at(index);
}


int Manager::count() const
{
    return m_contactList.count();
}


int Manager::privateContactCount() const
{
    return m_privateContactFinder.count();
}


int Manager::groupContactCount() const
{
    return m_groupContactFinder.count();
}


int Manager::size() const
{
    return m_contactList.size();
}


int Manager::privateContactSize() const
{
    return m_privateContactFinder.size();
}


int Manager::groupContactSize() const
{
    return m_groupContactFinder.size();
}


const Manager::ContactList &Manager::contacts() const
{
    return m_contactList;
}


void Manager::setActiveContact(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    if (m_activeContact == contact)
        return;

    m_activeContact = contact;
    emit activeContactChanged(m_activeContact);
}


AbstractContact *Manager::activeContact() const
{
    return m_activeContact;
}


bool Manager::isActiveContact(AbstractContact *contact) const
{
    if (contact == NULL)
        return false;

    return (m_activeContact == contact)? true : false;
}


void Manager::append(AbstractContact *contact)
{
    Q_ASSERT(contact);

    switch (contact->type()) {
    case AbstractContact::PrivateType:
        appendPrivateContact(contact);
        break;
    case AbstractContact::GroupType:
        appendGroupContact(contact);
        break;
    default:
        break;
    }
}


void Manager::appendPrivateContact(AbstractContact *contact)
{
    QMutexLocker locker(&m_mutex);
    Q_ASSERT(contact);
    if (contact->type() != AbstractContact::PrivateType)
        return;

    itemAboutToBeAppended(contact);
    m_contactList.append(contact);
    m_privateContactFinder.insert(contact->id(), contact);
    itemAppended(contact);
}


void Manager::appendGroupContact(AbstractContact *contact)
{
    QMutexLocker locker(&m_mutex);
    Q_ASSERT(contact);
    if (contact->type() != AbstractContact::GroupType)
        return;

    itemAboutToBeAppended(contact);
    m_contactList.append(contact);
    m_groupContactFinder.insert(contact->id(), contact);
    itemAppended(contact);
}


void Manager::insert(int position, AbstractContact *contact)
{
    if ((position < 0) || (position > count()))
        return;

    if (contact == NULL)
        return;

    switch (contact->type()) {
    case AbstractContact::PrivateType:
        insertPrivateContact(position, contact);
        break;
    case AbstractContact::GroupType:
        insertGroupContact(position, contact);
        break;
    default:
        break;
    }
}


void Manager::insertPrivateContact(int position, AbstractContact *contact)
{
    QMutexLocker locker(&m_mutex);
    if ((position < 0) || (position > count()))
        return;

    if (contact == NULL)
        return;

    itemAboutToBeAppended(contact);
    m_contactList.insert(position, contact);
    m_privateContactFinder.insert(contact->id(), contact);
    itemAppended(contact);
}


void Manager::insertGroupContact(int position, AbstractContact *contact)
{
    QMutexLocker locker(&m_mutex);
    if ((position < 0) || (position > count()))
        return;

    if (contact == NULL)
        return;

    itemAboutToBeAppended(contact);
    m_contactList.insert(position, contact);
    m_groupContactFinder.insert(contact->id(), contact);
    itemAppended(contact);
}


bool Manager::remove(AbstractContact *contact)
{
    QMutexLocker locker(&m_mutex);
    Q_ASSERT(contact);
    if (!contains(contact))
        return false;

    itemAboutToBeRemoved(contact);
    m_contactList.removeAll(contact);
    m_privateContactFinder.remove(contact->id());
    itemRemoved(contact);
    return true;
}


void Manager::itemAboutToBeAppended(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactAboutToBeAppended(contact);
}


void Manager::itemAppended(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactAppended(contact);
}


void Manager::itemAboutToBeRemoved(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactAboutToBeRemoved(contact);
}


void Manager::itemRemoved(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactRemoved(contact);
}


void Manager::itemAboutToBeUpdated(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactAboutToBeUpdated(contact);
}


void Manager::itemUpdated(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    emit contactUpdated(contact);
}


PrivateContact *Manager::createPrivateContact(const qint32 ownerId) const
{
    return new PrivateContact(ownerId);
}


GroupContact *Manager::createGroupContact(qint64 id) const
{
    return new GroupContact(id);
}


bool Manager::containsPrivateContact(qint32 id) const
{
    return m_privateContactFinder.contains(id);
}


bool Manager::containsGroupContact(qint64 id) const
{
    return m_groupContactFinder.contains(id);
}


bool Manager::contains(AbstractContact *contact) const
{
    if (contact == NULL)
        return false;

    if (m_contactList.isEmpty())
        return false;

    return m_contactList.contains(contact);
}


void Manager::clearData()
{
    clearPrivateContactFinder();
    clearGroupContactFinder();
    deleteContactList();
    emit dataCleared();
}


void Manager::deleteContactList()
{
    qDeleteAll(m_contactList);
    m_contactList.clear();
}


void Manager::clearPrivateContactFinder()
{
    m_privateContactFinder.clear();
}


void Manager::clearGroupContactFinder()
{
    m_groupContactFinder.clear();
}



void Manager::onContactDataChanged(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    if (!contains(contact))
        return;

    itemUpdated(contact);
}


void Manager::onLastContactTimeUpdated(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    if (!contains(contact))
        return;

    emit lastContactTimeUpdated(contact);
}


void Manager::onActiveContactChanged(AbstractContact *contact)
{
    if (contact == NULL)
        return;

    setActiveContact(contact);
}

} // namespace Contact
